<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
	</head>
	<body>
		<script>
			{
				// Object.create = function(obj) {
				// 	function F() {}
				// 	F.prototype = obj;
				// 	return new F();
				// };

				{
					// Object.getOwnPropertyNames() 返回的是对象中所有自己的属性;
					// Object.keys(obj) 则返回的对象中所有自己的属性，也就是属性下的 enumerable: true 的属性
					const obj = {};
					Object.defineProperties(obj, {
						name: {
							enumerable: true,
							value: 'alley'
						},
						age: {
							enumerable: false,
							value: 25
						},
					})
					console.log(Object.keys(obj), 'keys')
					console.log(Object.getOwnPropertyNames(obj), 'getOwnPropertyNames')
					// Array ["name"]
					//Array ["name", "age"]
				}

				function deepFreeze(obj) {
					var propsNames = Object.getOwnPropertyNames(obj);
					propsNames.forEach((item) => {
						var props = obj[item];
						if (props instanceof Object && props !== null) {
							deepFreeze(props);
						}
					})
					return Object.freeze(obj);
				}
				var obj = {
					name: 'alley',
					info: {
						age: 19,
						sex: '男'
					}
				}
				// Object.freeze(obj);
				deepFreeze(obj);
				obj.name = 'dy_alley';
				obj.info.age = 20;
				console.log(obj, 'oFreeze'); // { name: 'alley', info: { age: 19, sex: '男' } };
			} {
				const person = {
					isHuman: false,
					printIntroduction: function() {
						console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
					},
				};
				const me = Object.create(person, {
					age: {
						value: 42,
						writable: true,
						enumerable: true,
						configurable: true
					}
				});
				me.name = 'Matthew'; // "name" is a property set on "me", but not on "person"
				me.isHuman = true; // Inherited properties can be overwritten
				me.printIntroduction();
				console.log(me, 'me')
				console.log(me.__proto__, 'me__proto__')
				// Expected output: "My name is Matthew. Am I human? true"
			}

			{
				// Shape - 父类(superclass)
				function Shape() {
					this.x = 0;
					this.y = 0;
				}
				// 父类的方法
				Shape.prototype.move = function(x, y) {
					this.x += x;
					this.y += y;
					console.info('Shape moved.');
				};
				// Rectangle - 子类(subclass)
				function Rectangle() {
					Shape.call(this); // call super constructor.
				}
				// 子类续承父类
				Rectangle.prototype = Object.create(Shape.prototype);
				Rectangle.prototype.constructor = Rectangle;
				var rect = new Rectangle();
				// instance.__proto__ = instance.constructor.prototype
				// __proto__ => Object.getPrototypeOf()
				console.log('__proto__', rect.__proto__ === Rectangle.prototype);
				console.log('__proto__2', rect.__proto__ === rect.constructor.prototype);
				console.log('__proto__3', rect.constructor.prototype === Rectangle.prototype);
				console.log('Shape.prototype', Shape.prototype);
				console.log('Rectangle.prototype.__proto__', Rectangle.prototype.__proto__);
				console.log('Is rect an instance of Rectangle?', rect instanceof Rectangle); // true
				console.log('Is rect an instance of Shape?', rect instanceof Shape); // true
				rect.move(1, 1); // Outputs, 'Shape moved.'
			}

			{
				class P {
					static private = 'private'
					constructor() {
						this.age = 18
						return this
						return Object.create(null)
					}
					fn() {
						return this.age
					}
				}
				const NP = new P()
				console.log(P.prototype.constructor === P, 'constructor')
				console.log(NP.constructor === P.prototype.constructor, 'NP')
				console.log(NP instanceof P, 'instanceof P')
				console.log(NP.fn(), 'fn')
				class PP extends P {}
				console.log(PP.private, 'static')

				const IP = new class AB {
					static a = 'a'
					b = 'b'
					constructor(age) {
						this.age = age
					}
					fn() {
						// return AB.a
						return this.b
					}
				}(16)
				console.log(IP.fn(), 'IP.fn()')

				class Foo {
					constructor(...args) {
							this.args = args
						}
						*[Symbol.iterator]() { // 迭代器
							for (let arg of this.args) {
								yield arg
							}
						}
				}
				for (let x of new Foo('hello', 'world')) {
					console.log(x, 'iteratorX')
				}

				function* Generator(index) {
					while (index < 2) {
						yield index;
						index++;
					}
				}
				const iterator = Generator(0);
				console.log(iterator.next().value);
				// Expected output: 0
				console.log(iterator.next().value);
				// Expected output: 1
			}

			{
				class A {
					constructor() {
						this.x = 1
						console.log(new.target.name)
					}
				}
				class B extends A {
					constructor() {
						super() // A.prototype.constructor.call(this)
						this.x = 1
						super.x = 2
						console.log(super.x, 'super') // undefined
						console.log(this.x, 'this') // 2
					}
				}
				new A()
				new B()
			}
		</script>
	</body>
</html>